package ro.hex.remocadm.telnet;

import com.oroinc.net.telnet.TelnetClient;
import java.io.IOException;
import java.util.Properties;
import org.apache.log4j.Logger;

/**
 * Abstract class doing all the 'dirty' work for connecting to the remote
 * VLC telnet interface.
 * <br/>
 * It automatically does the connection and the login, the subclasses just need
 * to implement the telnetDialog() method and to use the functions 'readUnti',
 * 'writeLine' and 'getParameter'.
 *
 * @author Iulian Virtejanu
 */
public abstract class TelnetThread extends Thread {

    private Properties context;
    private TelnetClient tClient;
    private TelnetNotifier parent;
    private Logger logger = Logger.getLogger(TelnetThread.class);

    public TelnetThread(TelnetNotifier parent, Properties context) {
        this.parent = parent;
        this.context = context;
    }

    /**
     * Sets up the connection.
     */
    private void openConnection() throws IOException {
        String hostName = context.getProperty("vlc.admin.host");
        int port = Integer.parseInt(context.getProperty("vlc.admin.port"));

        tClient = new TelnetClient();
        tClient.connect(hostName, port);
    }

    @Override
    public void run() {
        parent.updateStatus(TelnetNotifier.START_EVENT, null);
        try {
            openConnection();

            login();

            telnetDialog();
        } catch (IOException ex) {
            parent.updateStatus(TelnetNotifier.ERROR_EVENT, ex);
        } finally {
            try {
                closeConnection();
            } catch (IOException ex) {
                parent.updateStatus(TelnetNotifier.ERROR_EVENT, ex);
            }
        }
        parent.updateStatus(TelnetNotifier.END_EVENT, null);
    }

    /**
     * Disconnects the telnet connection.
     * @throws IOException
     */
    private void closeConnection() throws IOException {
        if (tClient != null && tClient.isConnected()) {
            tClient.disconnect();
        }
    }

    /**
     * Implements the dialog on telnet using readUntil and writeLine methods.
     * @throws IOException
     */
    public abstract void telnetDialog() throws IOException;

    /**
     * Reads from the stream until 'lookFor' string is found.
     * @param lookFor
     * @return
     * @throws IOException
     */
    protected String readUntil(String lookFor) throws IOException {
        String string = "";
        while (true) {
            int value = tClient.getInputStream().read();
            string += (char) value;
            if (string.endsWith(lookFor)) {
                break;
            }
        }
        return string;
    }

    /**
     * Writes a line on the output stream.
     * @param string
     * @throws IOException
     */
    protected void writeLine(String string) throws IOException {
        for (int i = 0; i < string.length(); i++) {
            tClient.getOutputStream().write((char) string.charAt(i));
        }
        tClient.getOutputStream().write('\n');
        tClient.getOutputStream().flush();
    }

    /**
     * Returns the given parameter value from the context.
     * @param paramName
     * @return
     */
    protected String getParameter(String paramName) {
        return context.getProperty(paramName);
    }

    /**
     * Executes the login sequence, using the 'vlc.admin.pass' parameter
     * found in the context.
     * @throws IOException
     */
    protected void login() throws IOException {
        if (logger.isDebugEnabled()) {
            logger.debug(readUntil(": "));
        }
        writeLine(getParameter("vlc.admin.pass"));
        if (logger.isDebugEnabled()) {
            logger.debug(readUntil("> "));
        }
    }
}
